#include "PFileInfo.h"

namespace PComunicator
{


PFileInfo::PFileInfo(std::string theFullFilePath)
{
	mySize = 0;
	iss = NULL;
	this->myFullPath = theFullFilePath;
	GetInfo(theFullFilePath);
	ReadFile();
}


PFileInfo::PFileInfo(const std::vector<byte> &theEncodedFileInfo)
{
	iss = NULL;
	std::vector<byte>::const_iterator iterEnd;

	std::vector<byte> nameLenghtA;
	std::vector<byte> nameA;
	std::vector<byte> fileLenghtA;

	//nastavime na uplny zaciatok iterator
	iterEnd = theEncodedFileInfo.begin();

	myFile.reserve(theEncodedFileInfo.size()); //reservujeme si miesto, prinasa speed up

	//nakopirujeme do pomocneho vektoru prve 4 byte ktore predstavuju dlzku mena suboru
	std::copy(theEncodedFileInfo.begin(),iterEnd+=4,std::back_inserter(nameLenghtA));
	int aNameLenght = PConvertor::ToBasicType<int>(nameLenghtA); //z pola ziskame int s dlzkou slova

	//nastavime novy zaciatok iteratora
	std::vector<byte>::const_iterator iterStart = iterEnd;

	//nakopirujeme do pomocneho vektoru prave tolko bytov aka je dlzka kodovaneho mena
	std::copy(iterStart,iterEnd+=aNameLenght,std::back_inserter(nameA));
	std::string aName = PConvertor::ToString(nameA);	//z pola si ziskame meno suboru

	//novy zaciatok iteratora
	iterStart = iterEnd;

	//nakopirujeme si 4 nasledujuce bajty od bodu kde sa konci nazov suboru, tieto
	//4 byte predstavuju dlzku suboru
	std::copy(iterStart,iterEnd+=4,std::back_inserter(fileLenghtA));
	unsigned long aLenghtValue = 0;

	aLenghtValue = PConvertor::ToBasicType<unsigned long>(fileLenghtA);

	//prekopirujeme si do pola subora obsah samotneho suboru
	std::copy(iterEnd,theEncodedFileInfo.end(),std::back_inserter(myFile));

	GetInfo(aName,aLenghtValue);
}

PFileInfo::PFileInfo(std::string theFullFileName,std::istream *pIstream)
{
	iss = NULL;
	//nacitame subor z istream do vectora
	myFile.assign(std::istreambuf_iterator<char>((*pIstream)), std::istreambuf_iterator<char>());

	//ziskame dodatocne info
	GetInfo(theFullFileName,myFile.size());
}

PFileInfo::~PFileInfo(void)
{
	if(iss)
	{
		delete iss;
	}
	
}

PFileInfo::PFileInfo(const PFileInfo& fileInfo)
{
	this->myFile = fileInfo.myFile;
	this->mySize = fileInfo.mySize;
	this->myFileType = fileInfo.myFileType;
	this->myName = fileInfo.myName;
	this->myFullName = fileInfo.myFullName;
	this->myFullPath = fileInfo.myFullPath;

	std::string aString(myFile.begin(),myFile.end());
	iss = new std::istringstream(aString,std::istringstream::in | std::istringstream::out);
}


PFileInfo& PFileInfo::operator=(const PFileInfo& fileInfo)
{
	PFileInfo(fileInfo).Swap(*this);
	return *this;
}

unsigned long long PFileInfo::GetSize()
{
	return mySize;
}

std::string PFileInfo::GetName()
{
	if(myName.empty())
	{
		myName = myFullName;
	}
	return myName;
}

std::string PFileInfo::GetFullName()
{
	return myFullName;
}

std::string PFileInfo::GetFullPath()
{
	return myFullPath;
}

std::string PFileInfo::GetFileType()
{
	if(myFileType.empty())
	{
		std::size_t dot_index = myFullName.find_last_of('.');
		if(dot_index != std::string::npos)
		{
			myFileType = myFullName;
			myFileType = myFileType.erase(0,dot_index+1);
		}
	}
	return myFileType;
}

std::vector<byte> PFileInfo::GetFile()
{
	return myFile;
}

void PFileInfo::GetFileStream(std::istream **ptheStream)
{
	std::string aString(myFile.begin(),myFile.end());
	iss = new std::istringstream(aString,std::istringstream::in | std::istringstream::out);
	(*ptheStream) = new std::istream((*iss).rdbuf());
}

std::vector<byte> PFileInfo::FormatToArray()
{
	std::vector<byte> aFinalArray;

	std::vector<byte> aEncodedFileName = PConvertor::FromString(myFullName);
	std::vector<byte> aEncodedFileNameSize = PConvertor::FromBasicType<int>(static_cast<int>(aEncodedFileName.size()));
	std::vector<byte> aEncodedFileLenght = PConvertor::FromBasicType<unsigned long>(static_cast<unsigned long>(myFile.size()));

	std::copy(aEncodedFileNameSize.begin(),aEncodedFileNameSize.end(),std::back_inserter(aFinalArray));
	std::copy(aEncodedFileName.begin(),aEncodedFileName.end(),std::back_inserter(aFinalArray));
	std::copy(aEncodedFileLenght.begin(),aEncodedFileLenght.end(),std::back_inserter(aFinalArray));
	std::copy(myFile.begin(),myFile.end(),std::back_inserter(aFinalArray));

	return aFinalArray;
}

bool PFileInfo::Save(std::string theFullPath)
{
	if(theFullPath.empty() || myFullName.empty())
		return false;

	std::ofstream aNewFile((theFullPath+myFullName).c_str(),std::ios::out | std::ios::binary | std::ios::trunc);

	aNewFile.write((char*)&myFile[0],myFile.size());
	aNewFile.close();

	if(myFullPath.empty())
		myFullPath = theFullPath;

	return true;
}

//////////////////////////////////////////////////////////////////////
//Private Methods													//
//////////////////////////////////////////////////////////////////////

void PFileInfo::GetInfo(std::string theFile)
{
	if ( !boost::filesystem::is_regular(theFile) )
	{
		throw DataFileException(theFile);
	}

	mySize = boost::filesystem::file_size(theFile);

	std::pair<std::string,std::string> aPair = Tools::Separate(theFile,'\\',false);
	if( aPair.first.empty() || aPair.second.empty())
		aPair = Tools::Separate(theFile,'/',false);
	if( aPair.first.empty() || aPair.second.empty())
	{
		myFullPath = theFile;
		myFullName = theFile;

		aPair = Tools::Separate(myFullName,'.',false);
		if( aPair.first.empty() || aPair.second.empty())
			return;

		myName = aPair.first;
		myFileType = aPair.second;
		return;
	}
	else
	{
		myFullPath = aPair.first;
		myFullName = aPair.second;

		aPair = Tools::Separate(myFullName,'.',false);
		if( aPair.first.empty() || aPair.second.empty())
			return;

		myName = aPair.first;
		myFileType = aPair.second;
	}
}

void PFileInfo::GetInfo(std::string theFullName,unsigned long theSize)
{
	mySize = static_cast<long long>(theSize);

	std::pair<std::string,std::string> aPair = Tools::Separate(myFullName,'.',false);
	myName = aPair.first;
	myFileType = aPair.second;
	myFullName = theFullName;
}


void PFileInfo::ReadFile(void)
{
	std::string aFilePath;
	if(myFullPath != myFullName)
	{
		aFilePath = myFullPath + "\\" + myFullName;
	}
	else
	{
		aFilePath = myFullPath;
	}
	if ( !boost::filesystem::is_regular(aFilePath) )
	{
		throw DataFileException(myName);
	}

	std::ifstream aFile(aFilePath.c_str(),std::ios::in|std::ios::binary);
	if(aFile.is_open())
	{
		//nacita celi subor do vektora
		myFile.assign(std::istreambuf_iterator<char>(aFile), std::istreambuf_iterator<char>());
	}

	aFile.close();
}

void PFileInfo::Swap(PFileInfo& fileInfo)
{
	myFile.swap(fileInfo.myFile);
	std::swap(mySize,fileInfo.mySize);
	std::swap(myFileType,fileInfo.myFileType);
	std::swap(myName,fileInfo.myName);
	std::swap(myFullName,fileInfo.myFullName);
	std::swap(myFullPath,fileInfo.myFullPath);
	std::swap(iss,fileInfo.iss);
}

}